﻿using LoongCAD.Geometry;
using LoongCAD.Geometry.Friendly;
using LoongCAD.STC.Friendly.Dialog.UIControls;
using LoongCAD.STC.Friendly.Plugins;
using LoongCAD.STC.Friendly.Scene;
using LoongCAD.STC.Friendly.Scene.UI;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net.Http.Headers;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using static LoongCAD.STC.Friendly.Scene.BaseComponent;
using Plane = LoongCAD.Geometry.Friendly.Plane;

namespace ConnectionDemo
{
    //============组件通用属性=============
    [Plugin("ConnectionDemo")]                                          //组件名称
    [PluginUserInterface("Form_PluginMain")]                            //指定窗口类名称  
    [PluginNumber(9997)]                                                //组件编号
    //============节点组件属性=============
    [SecondaryType(ConnectionPlugin.SecondaryType.SECONDARYTYPE_ONE)]   //次零件个数
    public class ConnectionDemo : ConnectionPlugin
    {
        //当前创建的组件实例
        Connection comp;

        //组件窗口传入参数
        public StructuresData data;

        //用户场景输入参数
        Beam mainPart;
        Beam subPart;

        //自己建立的坐标系
        Matrix refMat;

        //=======创建过程相关的参数=========
        Plane mainFitPlane;
        Plane subFitPlane;

        ContourPlate plateY;
        ContourPlate plateNY;

        double mainWidth = 0.0;
        double mainHeight = 0.0;
        double webThickness = 0.0;

        List<double> hArray;
        List<double> vArray;

        public ConnectionDemo(StructuresData data)
        {
            this.data = data;
        }

        public override bool Run(Connection componentObject)
        {
            //获取用户场景输入参数
            comp = componentObject;
            mainPart = comp.PrimaryObject as Beam;
            subPart = comp.SecondaryObjects[0] as Beam;
            //输入合法性检查
            if (mainPart == null || subPart == null) return false;

            //计算参数
            CalcParams();
            //设置当前工作平面，之后的所有的几何数据(点，向量等)都会以这个工作平面为基准
            comp.Scene.SetCurrentTransformationPlane(new TransformationPlane(refMat));
            //创建对齐面
            CreateFitting();
            //创建板
            CreatePlate();
            //创建螺栓
            CreateBolts();
            //将当前工作平面还原
            refMat.Inverse();
            comp.Scene.SetCurrentTransformationPlane(new TransformationPlane(refMat));
            return true;
        }


        public void CalcParams()
        {
            //计算参考坐标系
            {
                //获取物体自身数据，当工作平面或物体本身发生变化的时候都需要获取一次以保证数据正确
                mainPart.Select();
                subPart.Select();
                List<Point> mainPoints = mainPart.GetCenterLine(false);
                List<Point> subPoints = subPart.GetCenterLine(false);

                Point mainMidPoint = (mainPoints[0] + mainPoints[1]) / 2;
                Point subMidPoint = (subPoints[0] + subPoints[1]) / 2;

                Point mainNearPoint = mainPoints[0];
                if (mainNearPoint.Distance(subMidPoint) > mainPoints[1].Distance(subMidPoint)) mainNearPoint = mainPoints[1];
                Point subNearPoint = subPoints[0];
                if(subNearPoint.Distance(mainMidPoint) > subPoints[1].Distance(mainMidPoint)) subNearPoint = subPoints[1];
                Point origin = (mainNearPoint + subNearPoint) / 2;

                Vector aixsX = new Vector(subMidPoint - mainMidPoint);
                aixsX.Normalize();
                CoordinateSystem coord = mainPart.GetCoordinateSystem();
                Vector aixsZ = new Vector(coord.AxisY);
                Vector aixsY = aixsZ.Cross(aixsX);

                refMat = new Matrix(origin, aixsX, aixsY, aixsZ);
#if DEBUG
                CreateAssistCoord(aixsX, aixsY, aixsZ, origin);
#endif
            }

            //获取零件截面数据
            {
                mainPart.GetReportProperty(PartReportProperties.PROFILE_FLANGE_WIDTH, out mainWidth);
                mainPart.GetReportProperty(PartReportProperties.PROFILE_HEIGHT, out mainHeight);
                mainPart.GetReportProperty(PartReportProperties.PROFILE_WEB_THICKNESS, out webThickness);
            }

            //计算螺栓数据
            {
                int hCount = data.boltHoriCount - 1;
                if (hCount < 0) hCount = 0;
                int vCount = data.boltVertCount - 1;
                if (vCount < 0) vCount = 0;

                hArray = new List<double>();
                vArray = new List<double>();
                for (int i = 0; i < hCount; i++) hArray.Add(data.boltHoriDist);
                for (int i = 0; i < vCount; i++) vArray.Add(data.boltVertDist);
            }
        }

        //绘制创建的坐标系
        void CreateAssistCoord(Vector dirX, Vector dirY, Vector dirZ, Point p0, double len = 1000)
        {
            //O
            ControlPoint cp = new ControlPoint();
            cp.Point = new Point(p0);
            cp.Insert();

            //X
            ControlLine x = new ControlLine();
            x.Line = new LineSegment(new Point(p0), new Point(p0 + dirX * len));
            x.Color = new Color(1.0, 0.0, 0.0);
            x.Extension = 100;
            x.Insert();
            //y
            ControlLine y = new ControlLine();
            y.Line = new LineSegment(new Point(p0), new Point(p0 + dirY * len));
            y.Color = new Color(0.0, 1.0, 0.0);
            y.Extension = 100;
            y.Insert();
            //z
            ControlLine z = new ControlLine();
            z.Line = new LineSegment(new Point(p0), new Point(p0 + dirZ * len));
            z.Color = new Color(0.0, 0.0, 1.0);
            z.Extension = 100;
            z.Insert();
        }

        void CreateFitting()
        {
            //创建次零件对齐
            {
                Point o = new Point(data.beamDist / 2, 0, 0);
                subFitPlane = new Plane(o, Vector.AXIS_X);
                Fitting fit = new Fitting();
                fit.CutTarget = subPart;
                fit.Plane = subFitPlane.Clone();
                fit.Insert();
            }

            //创建主零件对齐
            {
                Point o = new Point(-data.beamDist / 2, 0, 0);
                mainFitPlane = new Plane(o, -Vector.AXIS_X);
                Fitting fit = new Fitting();
                fit.CutTarget = mainPart;
                fit.Plane = mainFitPlane.Clone();
                fit.Insert();
            }
        }

        void CreatePlate()
        {
            Point p0 = new Point(0, 0, 0);
            double thickness = data.plateProps.Thickness;
            double width = data.boltMarginT * 2 + vArray.Sum();
            double moveX = data.beamDist / 2 + data.boltMarginL + hArray.Sum() + data.boltMarginR;
            if (data.platePos != double.MaxValue)
            {
                p0 = p0 + Vector.AXIS_Z * (mainHeight / 2 - width / 2 - data.platePos);
            }


            ContourPlate CreateOnePlate(Vector dirY)
            {
                //计算板的控制点位置
                Point p = p0 + dirY * (webThickness / 2 + thickness / 2);

                Point p1 = p + Vector.AXIS_X * (moveX);
                p1 = p1 + Vector.AXIS_Z * (width / 2);

                Point p2 = p1 - Vector.AXIS_Z * (width);

                Point p3 = p2 - Vector.AXIS_X * (moveX * 2);

                Point p4 = p3 + Vector.AXIS_Z * (width);

                //=======创建板并设置属性========
                ContourPlate plate = new ContourPlate();
                //板的控制点(会随工作平面变化而变化)
                //当工作平面变化时，需要调用对象的Select()函数来获取它在当前工作平面下的位置属性
                ContourPoint cp1 = new ContourPoint(p1, new Chamfer());
                ContourPoint cp2 = new ContourPoint(p2, new Chamfer());
                ContourPoint cp3 = new ContourPoint(p3, new Chamfer());
                ContourPoint cp4 = new ContourPoint(p4, new Chamfer());
                plate.AddContourPoint(cp1);
                plate.AddContourPoint(cp2);
                plate.AddContourPoint(cp3);
                plate.AddContourPoint(cp4);
                //板的空间位置属性(会随工作平面变化而变化）
                //当工作平面变化时，需要调用对象的Select()函数来获取它在当前工作平面下的位置属性
                plate.Position.Depth = Position.DepthEnum.MIDDLE;
                plate.Position.DepthOffset = 0;

                //板的业务逻辑属性
                plate.Profile.ProfileString = "PL" + thickness;
                plate.Class = "7";
                plate.Material.MaterialString = data.plateProps.Material;
                plate.Name = data.plateProps.Name;
                plate.PartNumber.Prefix = data.plateProps.NoPrefix;
                //向主程序发送创建指令
                plate.Insert();

                return plate;
            }

            //向工作平面的Y方向创建板
            plateY = CreateOnePlate(Vector.AXIS_Y);
            //向工作平面的-Y方向创建板
            plateNY = CreateOnePlate(-Vector.AXIS_Y);
        }

        void CreateBolts()
        {
            Point p0 = new Point(0, webThickness / 2, 0);
            double thickness = data.plateProps.Thickness;
            double width = data.boltMarginT * 2 + vArray.Sum();
            double moveX = data.beamDist / 2 + data.boltMarginL + hArray.Sum() + data.boltMarginR;
            if (data.platePos != double.MaxValue)
            {
                p0 = p0 + Vector.AXIS_Z * (mainHeight / 2 - width / 2 - data.platePos);
            }

            void CreateOneBolt(Vector dirX, Part target)
            {
                Point p1 = p0 + dirX * (data.boltMarginL);
                Point p2 = p1 + dirX * (hArray.Sum() + data.boltMarginR);

                //=======创建螺栓并设置属性========
                BoltArray bolts = new BoltArray();
                //螺栓控制点(会随工作平面变化而变化)
                //当工作平面变化时，需要调用对象的Select()函数来获取它在当前工作平面下的位置属性
                bolts.FirstPosition = p1;
                bolts.SecondPosition = p2;
                //螺栓空间位置属性(会随工作平面变化而变化）
                //当工作平面变化时，需要调用对象的Select()函数来获取它在当前工作平面下的位置属性
                bolts.Position.Rotation = Position.RotationEnum.FRONT;
                bolts.Position.RotationOffset = 0;

                //螺栓业务逻辑属性
                bolts.PartToBoltTo = target;
                bolts.PartToBeBolted = plateY;
                bolts.OtherPartsToBolt.Add(plateNY);
                foreach (double d in hArray) bolts.AddBoltDistX(d);
                foreach (double d in vArray) bolts.AddBoltDistY(d);
                bolts.BoltStandard = data.boltBasicProps.BoltStandard;
                bolts.BoltSize = data.boltBasicProps.BoltSize;
                bolts.ThreadInMaterial = false;
                bolts.BoltType = BoltGroup.BoltTypeEnum.BOLT_TYPE_SITE;
                bolts.Tolerance = data.boltBasicProps.HoleTol;

                bolts.SlottedHoleX = data.boltHoleProps.HoleX;
                bolts.SlottedHoleY = data.boltHoleProps.HoleY;
                switch (data.boltHoleProps.HoleType)
                {
                    case 0:
                    case 1:
                        bolts.HoleType = BoltGroup.BoltHoleTypeEnum.HOLE_TYPE_SLOTTED;
                        break;
                    case 2:
                        bolts.HoleType = BoltGroup.BoltHoleTypeEnum.HOLE_TYPE_OVERSIZED;
                        break;
                }
                switch (data.boltHoleProps.RotSlot)
                {
                    case 0:
                        bolts.RotateSlots = BoltGroup.BoltRotateSlotsEnum.ROTATE_SLOTS_ODD;
                        break;
                    case 1:
                        bolts.RotateSlots = BoltGroup.BoltRotateSlotsEnum.ROTATE_SLOTS_EVEN;
                        break;
                    case 2:
                        bolts.RotateSlots = BoltGroup.BoltRotateSlotsEnum.ROTATE_SLOTS_PARALLEL;
                        break;
                }
                bolts.Hole1 = false;
                bolts.Hole2 = false;
                bolts.Hole3 = false;
                bolts.Hole4 = false;
                bolts.Hole5 = false;
                switch (data.boltHoleProps.SlotIn)
                {
                    case 0:
                        bolts.Hole1 = true;
                        bolts.Hole2 = true;
                        bolts.Hole3 = true;
                        break;
                    case 1:
                        break;
                    case 2:
                        bolts.Hole2 = true;
                        break;
                    case 3:
                        bolts.Hole1 = true;
                        bolts.Hole3 = true;
                        break;
                    case 4:
                        bolts.Hole1 = true;
                        bolts.Hole2 = true;
                        bolts.Hole3 = true;
                        break;

                }

                bolts.Washer1 = data.boltContentProps.WasherUp;
                bolts.Washer2 = data.boltContentProps.WasherDown0;
                bolts.Washer3 = data.boltContentProps.WasherDown1;
                bolts.Nut1 = data.boltContentProps.Nut0;
                bolts.Nut2 = data.boltContentProps.Nut1;

                bolts.ExtraLength = data.boltExtendProps.ExtLength;
                //向主程序发送螺栓创建指令
                bolts.Insert();
            }

            //在次零件端创建螺栓
            CreateOneBolt(Vector.AXIS_X, subPart);
            //在主零件端创建螺栓
            CreateOneBolt(-Vector.AXIS_X, mainPart);

        }
    }
}
